package org.jetlinks.pro.tenant.annotation;

import org.jetlinks.pro.assets.annotation.AssetsController;
import org.jetlinks.pro.tenant.TenantAssetManager;
import org.springframework.core.annotation.AliasFor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.annotation.*;
import java.util.Collection;

/**
 * 在需要租户权限控制的Controller类和方法上标记此注解,实现租户数据权限控制.
 *
 * <ul>
 *     <li>支持带有动态查询参数{@link org.hswebframework.web.api.crud.entity.QueryParamEntity}的方法</li>
 *     <li>支持根据参数中的id进行控制,{@link TenantAssets#assetIdIndex()}.(默认)</li>
 *     <li>支持根据参数中的对象属性进行控制,{@link TenantAssets#assetObjectIndex()}</li>
 *     <li>支持自动绑定资产(通常在新增时),{@link TenantAssets#autoBind()}.</li>
 *     <li>支持自动解绑绑定资产(通常在删除时),{@link TenantAssets#autoUnbind()}</li>
 * </ul>
 *
 * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController
 * @see org.jetlinks.pro.tenant.crud.TenantCorrelatesAccessCrudController
 * @see org.jetlinks.pro.tenant.crud.TenantCorrelatesAccessQueryController
 * @see AssetsController
 * @since 1.5
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@AssetsController
public @interface TenantAssets {

    /**
     * 资产类型,类和方法上的注解不能同时为空.
     *
     * @return 资产类型标识
     * @see org.jetlinks.pro.tenant.AssetType
     */
    @AliasFor(annotation = AssetsController.class)
    String type() default "";

    /**
     * 方法参数中,资产ID对应的索引.通常用于 根据id进行某个操作时.比如:根据id查询,根据id修改.
     * @return 资产ID参数索引
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#update(Object, Mono)
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#getById(Object)
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#delete(Object)
     */
    @AliasFor(annotation = AssetsController.class)
    int assetIdIndex() default 0;

    /**
     * 方法参数中,资产对象的索引,默认为-1,表示不使用对象来进行租户相关控制,而使用{@link TenantAssets#assetIdIndex()}来处理
     *
     * @return 资产对象参数索引
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#save(Flux)
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#add(Mono)
     */
    @AliasFor(annotation = AssetsController.class)
    int assetObjectIndex() default -1;

    /**
     * 用于在动态查询时,自动追加查询条件: where(property(),"assets",assetTerm);
     *
     * @return 资产ID对应属性
     * @see org.jetlinks.pro.tenant.term.AssetsTerm
     * @see org.jetlinks.pro.tenant.term.TenantMemberAssetsTermBuilder
     */
    @AliasFor(annotation = AssetsController.class)
    String property() default "id";

    /**
     * 要求当前用户必须是租户,当设置为true时,没有分配租户信息的用户将无法访问此功能.
     *
     * @return 默认为false
     */
    @AliasFor(annotation = AssetsController.class)
    boolean required() default false;

    /**
     * 是否自动绑定资产, 通用用于新增数据的时候将新增的实体类自动绑定到用户资产下
     *
     * @return 自动绑定
     * @see TenantAssetManager#bindAssetsOwner(String, org.jetlinks.pro.assets.AssetType, String, Collection)
     * @see org.jetlinks.pro.tenant.TenantMember#bindAssets(String, Collection)
     */
    @AliasFor(annotation = AssetsController.class)
    boolean autoBind() default false;

    /**
     * 是否自动解绑, 通用用于删除数据的时候,将资产解绑
     *
     * @return 自动绑定
     * @see TenantAssetManager#unbindAssetsOwner(org.jetlinks.pro.assets.AssetType, Collection, Collection)
     * @see org.jetlinks.pro.tenant.TenantMember#unbindAssets(String, Collection)
     */
    @AliasFor(annotation = AssetsController.class)
    boolean autoUnbind() default false;

    /**
     * 是否解绑所有的资产,当删除数据时,解绑所有租户下的此资产。
     * 当{@link TenantAssets#autoUnbind()}为true是有效
     *
     * @return 是否绑定全部
     * @see TenantAssetManager#unbindAllAssets(String, Collection)
     * @since 1.9
     */
    @AliasFor(annotation = AssetsController.class)
    boolean unbindAll() default true;

    /**
     * 是否执行校验,通常用于新增数据的时候,设置为false则不校验传入的数据.
     *
     * @return 是否执行校验
     */
    @AliasFor(annotation = AssetsController.class)
    boolean validate() default true;

    /**
     * @return 忽略处理租户权限信息
     */
    @AliasFor(annotation = AssetsController.class)
    boolean ignore() default false;

    /**
     * @return 忽略处理动态查询条件
     */
    @AliasFor(annotation = AssetsController.class)
    boolean ignoreQuery() default false;

    /**
     * 适用于 save or update时
     *
     * @return 当资产不存在时是否通过检查
     * @see org.jetlinks.pro.tenant.crud.TenantAccessCrudController#save(Flux)
     */
    @AliasFor(annotation = AssetsController.class)
    boolean allowAssetNotExist() default false;

    @AliasFor(annotation = AssetsController.class)
    String[] permission() default {};
}
